import os
import datetime
import json
import re
import calendar
import pandas as pd
from openpyxl import load_workbook
import sqlite3
from tkinter import ttk,Tk, messagebox, filedialog, Button, Frame, Text, Scrollbar, StringVar, OptionMenu, Label, Canvas, Toplevel, Entry  # 导入 Toplevel 和 Entry
from tkinter.ttk import Style, Notebook  # 导入Notebook用于创建选项卡
import threading

# 创建Tkinter根窗口
root = Tk()
root.title("称重记录工具")
root.geometry("600x600")

# 设置样式
style = Style()
style.configure('TButton', font=('Arial', 12), padding=6, width=20)  # 设置按钮宽度以保持一致大小
style.configure('TLabel', font=('Arial', 12))

# 创建选项卡控件
notebook = Notebook(root)

# 创建第一个选项卡
frame_main = Frame(notebook)
notebook.add(frame_main, text="数据导入/导出")

# 创建第二个选项卡用于切换数据源
frame_switch = Frame(notebook)
notebook.add(frame_switch, text="切换年份")

# 显示选项卡
notebook.pack(expand=1, fill='both')

# 创建日志文本框
log_frame = Frame(frame_main)
log_frame.pack(fill='both', expand=True, pady=(10, 0))
scrollbar = Scrollbar(log_frame)
scrollbar.pack(side='right', fill='y')
log_text = Text(log_frame, wrap='word', yscrollcommand=scrollbar.set, font=('Arial', 12))
log_text.pack(fill='both', expand=True)
scrollbar.config(command=log_text.yview)

# JSON配置文件路径
config_file = '数据库表名.json'

# 初始化配置文件
default_config = {
    'db_path': r"\\Lmdsz\f\2024年台账\称重记录.db",
    'table_name': '称重记录2024'
}
if not os.path.exists(config_file):
    with open(config_file, 'w') as f:  # 指定编码为 utf-8
        json.dump(default_config, f, ensure_ascii=False) # 确保非ASCII字符直接写入
        db_path = default_config.get('db_path')
        table_name = default_config.get('table_name')
else:
    with open(config_file, 'r') as f:  # 读取时也指定编码为 utf-8
        config = json.load(f)
        db_path = config.get('db_path')
        table_name = config.get('table_name')

# 创建数据库连接
conn = sqlite3.connect(db_path)
cursor = conn.cursor()

# 创建表结构（如果表不存在）
create_table_query = f"""
CREATE TABLE IF NOT EXISTS {table_name} (
    编号 TEXT PRIMARY KEY,
    第一次 REAL,
    第二次 REAL,
    是否已使用 TEXT DEFAULT '',
    用于何处 TEXT DEFAULT ''
);
"""
cursor.execute(create_table_query)

# 验证编号格式
def validate_id(id_str):
    if len(id_str) != 7:
        return False
    prefix = id_str[0]
    month = int(id_str[1:3])
    day = int(id_str[3:5])
    seq = int(id_str[5:])
    if prefix not in ['A', 'B', 'C']:
        return False
    if not (1 <= month <= 12):
        return False
    if not (1 <= seq <= 99):
        return False
    # Check the day based on the actual month and year
    year = datetime.datetime.now().year
    _, last_day = calendar.monthrange(year, month)
    if not (1 <= day <= last_day):
        return False
    return True

# 验证差值
def check_difference(prefix, first_val, second_val):
    diff = abs(first_val - second_val)
    if prefix == 'A' and diff >= 0.0001:
        return False
    elif prefix == 'B' and diff >= 0.0005:
        return False
    elif prefix == 'C' and diff >= 0.0002:
        return False
    return True

# 导入数据到数据库
def import_data_to_db():
    def do_import():
        try:
            # 创建一个新的数据库连接和游标
            conn = sqlite3.connect(db_path)
            cursor = conn.cursor()

            file_path = filedialog.askopenfilename(title="选择称重记录文件",
                                                   filetypes=[("Excel files", "*.xlsx;*.xlsm")])
            if not file_path:
                log_text.insert('end', "错误: 未选择文件\n")
                return
            keep_vba = file_path.endswith('.xlsm')
            wb = load_workbook(file_path, keep_vba=keep_vba)  # 根据文件扩展名决定是否保持宏的完整性
            all_data = []
            for sheet_name in wb.sheetnames[:3]:  # 只处理前三个工作表
                df = pd.read_excel(file_path, sheet_name=sheet_name)
                invalid_ids = []
                for index, row in df.iterrows():
                    id_str = row['编号']
                    first_val = row['第一次']
                    second_val = row['第二次']
                    if not validate_id(id_str) or not check_difference(id_str[0], first_val, second_val):
                        invalid_ids.append(id_str)
                if invalid_ids:
                    error_message = f"工作表 {sheet_name} 中以下编号不符合规则要求：\n" + "\n".join(invalid_ids)
                    raise ValueError(error_message)
                all_data.extend([(row['编号'], row['第一次'], row['第二次']) for _, row in df.iterrows() if
                                 row['编号'] not in invalid_ids])
            with conn:
                conn.executemany(f"""
                    INSERT INTO {table_name} (编号, 第一次, 第二次)
                    VALUES (?, ?, ?)
                    ON CONFLICT(编号) DO UPDATE SET
                    第一次=excluded.第一次,
                    第二次=excluded.第二次;
                """, all_data)
            log_text.insert('end', "数据导入完成\n")
            messagebox.showinfo("完成", "数据导入完成")
        except Exception as e:
            log_text.insert('end', f"发生错误: {e}\n")
            messagebox.showerror("错误", f"发生错误: {e}")
        finally:
            # 关闭数据库连接
            conn.close()

    threading.Thread(target=do_import).start()

# 在目标工作表中更新数据并更新数据库记录
def update_data_in_sheet(ws, db_df, success_flag):
    for index, row in db_df.iterrows():
        found = False
        for cell in ws['B']:
            if cell.value == row['编号']:
                ws.cell(row=cell.row, column=8, value=row['第一次'])
                ws.cell(row=cell.row, column=9, value=row['第二次'])
                found = True
                break
        if not found:
            log_text.insert('end', f"编号 {row['编号']} 未找到对应单元格。\n")
            success_flag[0] = False  # 如果有一个编号未找到对应单元格，标记操作不成功

# 从数据库导出数据到Excel
def export_data_from_db():
    log_text.delete(1.0, 'end')
    file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx;*.xlsm")])
    if not file_path:
        log_text.insert('end', "错误: 未选择文件\n")
        return
    workbook_name = os.path.splitext(os.path.basename(file_path))[0]
    success = True  # 标记操作是否成功
    updated_codes = set()  # 存储已成功更新的编号集合
    try:
        keep_vba = file_path.endswith('.xlsm')
        wb = load_workbook(file_path, keep_vba=keep_vba)  # 根据文件扩展名决定是否保持宏的完整性
        sheet_names = wb.sheetnames
        log_messages = []
        missing_codes = set()  # 存储缺失的编号
        for excel_sheet in ['TSP2', '颗粒物1', '低浓度颗粒物1', '沥青烟（有组织）2']:
            if excel_sheet in sheet_names:
                ws = wb[excel_sheet]
                codes = [cell.value for cell in ws['B'] if cell.value and re.match(r'[ABC]', str(cell.value))]
                # 检查是否有编号已经使用
                if codes:
                    used_codes = {code for code, usage_status, _ in cursor.execute(
                        f"SELECT 编号, 是否已使用, 用于何处 FROM {table_name} WHERE 编号 IN ({', '.join(['?'] * len(codes))})",
                        codes) if usage_status == '是'}
                    for code in used_codes:
                        log_messages.append(
                            f"编号 {code} 已经使用于 {cursor.execute('SELECT 用于何处 FROM {table_name} WHERE 编号=?', (code,)).fetchone()[0]}。")
                        log_text.insert('end', log_messages[-1] + '\n')
                        success = False  # 如果有编号已经使用，则标记操作不成功
                else:
                    log_text.insert('end', "没有需要检查的编号。\n")
                # 检查是否有编号不在数据库中
                existing_codes = {code for code, in cursor.execute(
                    f"SELECT 编号 FROM {table_name} WHERE 编号 IN ({', '.join(['?'] * len(codes))})", codes)}
                missing_codes.update(set(codes) - existing_codes)
        if missing_codes:
            log_text.insert('end', "不存在的编号为:\n" + "\n".join(missing_codes) + "\n")
            messagebox.showwarning("警告", "存在编号在数据库中找不到匹配项，操作已取消。")
            success = False
        if success:
            for excel_sheet in ['TSP2', '颗粒物1', '低浓度颗粒物1', '沥青烟（有组织）2']:
                if excel_sheet in sheet_names:
                    ws = wb[excel_sheet]
                    codes = [cell.value for cell in ws['B'] if cell.value and re.match(r'[ABC]', str(cell.value))]
                    query = f"SELECT 编号, 第一次, 第二次 FROM {table_name} WHERE 编号 IN ({', '.join(['?'] * len(codes))}) AND 编号 NOT IN ({', '.join(['?'] * len(used_codes))})"
                    rows = cursor.execute(query, codes + list(used_codes)).fetchall()
                    db_df = pd.DataFrame(rows, columns=['编号', '第一次', '第二次'])
                    update_data_in_sheet(ws, db_df, [success])
                    # 将成功写入的编号添加到集合中
                    updated_codes.update(db_df['编号'])
            wb.save(file_path)
            log_text.insert('end', "数据导出完成\n")
            messagebox.showinfo("完成", "数据导出完成")
            # 统一更新数据库中的编号使用情况和编号所在单号
            for code in updated_codes:
                cursor.execute(f"""
                    UPDATE {table_name}
                    SET 是否已使用 = '是', 用于何处 = ?
                    WHERE 编号 = ?
                """, (workbook_name, code))
    except PermissionError as pe:
        log_text.insert('end', "错误: 目标工作簿处于打开状态，请关闭后重新操作。\n")
    except Exception as e:
        log_text.insert('end', f"发生错误: {e}\n")
        messagebox.showerror("错误", f"发生错误: {e}")
    finally:
        conn.commit()
# 全球字典来跟踪窗口状态
window_dict = {}

# 窗口关闭事件处理函数
def on_window_close(window_key):
    if window_key in window_dict:
        window_dict[window_key].destroy()
        del window_dict[window_key]
# 手动添加数据的弹窗函数
# 手动添加数据的弹窗函数
def show_add_data_popup():
    if 'add_data_popup' in window_dict and window_dict['add_data_popup'].winfo_exists():
        window_dict['add_data_popup'].deiconify()  # 如果窗口已存在，恢复窗口
    else:
        create_add_data_popup()  # 如果窗口不存在，创建新窗口

# 创建手动添加数据的弹窗
def create_add_data_popup():
    def generate_ids():
        category_date = entry_category_date.get()
        number_range = entry_number_range.get()
        if not re.match(r'^[ABC]\d{4}$', category_date):
            messagebox.showerror("错误", "编号前五位格式不正确，应为 A0101 形式。")
            return []
        if not re.match(r'^\d{2}-\d{2}$', number_range):
            messagebox.showerror("错误", "编号范围格式不正确，应为 01-99 形式。")
            return []
        start, end = map(int, number_range.split('-'))
        if not (1 <= start <= 99) or not (1 <= end <= 99) or start > end:
            messagebox.showerror("错误", "编号范围不合法。")
            return []
        ids = [f"{category_date}{str(i).zfill(2)}" for i in range(start, end + 1)]
        return ids

    def show_input_fields():
        # 销毁之前的输入框架（如果存在的话）
        if hasattr(popup, 'input_frame'):
            popup.input_frame.destroy()
        ids = generate_ids()
        if not ids:
            return
        # 创建新的输入框架
        popup.input_frame = Frame(popup)
        popup.input_frame.grid(row=3, column=0, columnspan=20, sticky='nsew')
        canvas = Canvas(popup.input_frame)
        scrollbar = Scrollbar(popup.input_frame, orient='vertical', command=canvas.yview)
        scrollable_input_frame = Frame(canvas)
        scrollable_input_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )
        canvas.create_window((0, 0), window=scrollable_input_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        # 设置输入框架的最小大小
        popup.input_frame.grid_columnconfigure(0, weight=1)
        popup.input_frame.grid_columnconfigure(1, weight=1)
        popup.input_frame.grid_rowconfigure(0, weight=1)
        # 设置 canvas 的大小
        canvas.config(width=350, height=400)  # 调整 canvas 大小
        # 添加滚动条和画布到窗口
        scrollbar.grid(row=0, column=1, sticky='ns')
        canvas.grid(row=0, column=0, sticky='nsew')
        row = 0
        first_entries = {}
        second_entries = {}
        for id_str in ids:
            Label(scrollable_input_frame, text=f" {id_str}").grid(row=row, column=1, padx=10, pady=5)
            first_entry = Entry(scrollable_input_frame)
            first_entry.grid(row=row, column=2, padx=2, pady=4)
            first_entries[id_str] = first_entry
            second_entry = Entry(scrollable_input_frame)
            second_entry.grid(row=row, column=3, padx=2, pady=4)
            second_entries[id_str] = second_entry
            row += 1
        # 将输入字段字典保存为全局变量，以便在添加数据时使用
        popup.first_entries = first_entries
        popup.second_entries = second_entries

    def add_data_to_db():
        # 使用 popup.first_entries 和 popup.second_entries 获取输入数据
        data_entries = []
        for id_str in popup.first_entries.keys():
            first_val = float(popup.first_entries[id_str].get())
            second_val = float(popup.second_entries[id_str].get())
            if not validate_id(id_str) or not check_difference(id_str[0], first_val, second_val):
                log_text.insert('end', f"错误: 编号 {id_str} 或称重值不符合规则要求。\n")
                messagebox.showerror("错误", f"编号 {id_str} 或称重值不符合规则要求。")
                return
            data_entries.append((id_str, first_val, second_val))
        try:
            with conn:
                conn.executemany(f"""
                    INSERT INTO {table_name} (编号, 第一次, 第二次)
                    VALUES (?, ?, ?)
                    ON CONFLICT(编号) DO UPDATE SET
                    第一次=excluded.第一次,
                    第二次=excluded.第二次;
                """, data_entries)
            log_text.insert('end', "数据添加成功\n")
            messagebox.showinfo("完成", "数据添加成功")
            popup.destroy()
        except Exception as e:
            log_text.insert('end', f"发生错误: {e}\n")
            messagebox.showerror("错误", f"发生错误: {e}")

    popup = Toplevel(root)
    window_dict['add_data_popup'] = popup  # 将窗口对象存储到字典中
    popup.title("添加数据到数据库")
    popup.geometry("400x600")  # 增大弹窗的整体大小
    screen_width = popup.winfo_screenwidth()
    screen_height = popup.winfo_screenheight()
    x = (screen_width - 400) // 2
    y = (screen_height - 600) // 2
    popup.geometry(f"400x600+{x}+{y}")
    # 设置行和列权重，使输入框架能够扩展填充可用空间
    popup.grid_rowconfigure(3, weight=1)
    popup.grid_columnconfigure(2, weight=1)
    # 编号前五位
    Label(popup, text="编号前五位 (格式: A0101):").grid(row=0, column=0, padx=2, pady=2)
    entry_category_date = Entry(popup)
    entry_category_date.grid(row=0, column=1, padx=2, pady=2)
    # 编号范围
    Label(popup, text="编号范围 (格式: 01-99):").grid(row=1, column=0, padx=2, pady=2)
    entry_number_range = Entry(popup)
    entry_number_range.grid(row=1, column=1, padx=2, pady=2)
    # 生成数据输入框按钮
    btn_generate = Button(popup, text="生成数据输入框", command=show_input_fields)
    btn_generate.grid(row=2, column=0, columnspan=2, pady=10)
    # 添加数据按钮
    btn_add = Button(popup, text="添加数据", command=add_data_to_db)
    btn_add.grid(row=5, column=1, columnspan=1, pady=10)
    # 绑定关闭事件
    popup.protocol("WM_DELETE_WINDOW", lambda: on_window_close('add_data_popup'))


# 查找并修改数据的弹窗函数
def search_and_edit_data():
    if 'search_edit_popup' in window_dict and window_dict['search_edit_popup'].winfo_exists():
        window_dict['search_edit_popup'].deiconify()  # 如果窗口已存在，恢复窗口
    else:
        create_search_edit_popup()  # 如果窗口不存在，创建新窗口

# 创建查找并修改数据的弹窗
def create_search_edit_popup():
    def search_data():
        nonlocal scrollable_frame

        query_text = entry_query.get().strip()
        if not query_text:
            messagebox.showwarning("警告", "请输入查询内容。")
            return

        conditions = []
        params = []

        if search_by.get() == "id":
            if not re.match(r'^[ABC]\d{4,6}$', query_text):
                messagebox.showerror("错误", f"编号前缀格式不正确。")
                return
            conditions.append("编号 LIKE ?")
            params.append(f"{query_text}%")
        elif search_by.get() == "where_used":
            conditions.append("用于何处 LIKE ?")
            params.append(f"%{query_text}%")

        query_conditions = " AND ".join(conditions) if conditions else "1=1"
        cursor.execute(f"""
            SELECT 编号, 第一次, 第二次, 是否已使用, 用于何处 
            FROM {table_name} 
            WHERE {query_conditions}
        """, params)
        results = cursor.fetchall()

        if results:
            for widget in frame_details.winfo_children():
                widget.destroy()

            canvas = Canvas(frame_details)
            scrollbar = Scrollbar(frame_details, orient='vertical', command=canvas.yview)
            scrollable_frame = Frame(canvas)

            scrollable_frame.bind(
                "<Configure>",
                lambda e: canvas.configure(
                    scrollregion=canvas.bbox("all")
                )
            )

            canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
            canvas.configure(yscrollcommand=scrollbar.set)

            # 创建列标题
            Label(scrollable_frame, text="编号").grid(row=0, column=0, padx=10, pady=5)
            Label(scrollable_frame, text="第一次").grid(row=0, column=1, padx=10, pady=5)
            Label(scrollable_frame, text="第二次").grid(row=0, column=2, padx=10, pady=5)
            Label(scrollable_frame, text="是否已使用").grid(row=0, column=3, padx=10, pady=5)
            Label(scrollable_frame, text="用于何处").grid(row=0, column=4, padx=10, pady=5)

            # 显示查询结果
            for idx, result in enumerate(results, start=1):
                id_var = StringVar(value=result[0])
                first_var = StringVar(value=str(result[1]))
                second_var = StringVar(value=str(result[2]))
                used_var = StringVar(value=result[3])
                where_used_var = StringVar(value=result[4])

                Label(scrollable_frame, textvariable=id_var).grid(row=idx, column=0, padx=8, pady=5)
                Entry(scrollable_frame, textvariable=first_var).grid(row=idx, column=1, padx=8, pady=5)
                Entry(scrollable_frame, textvariable=second_var).grid(row=idx, column=2, padx=10, pady=5)
                Entry(scrollable_frame, textvariable=used_var).grid(row=idx, column=3, padx=4, pady=5)
                Entry(scrollable_frame, textvariable=where_used_var).grid(row=idx, column=4, padx=15, pady=5)

            scrollbar.pack(side='right', fill='y')
            canvas.pack(side='left', fill='both', expand=True)
            frame_details.pack(pady=10)
        else:
            messagebox.showwarning("警告", "未找到符合条件的数据。")

    def save_changes():
        changes = []
        for child in scrollable_frame.winfo_children():
            if isinstance(child, Entry):
                row = child.grid_info()['row']
                col = child.grid_info()['column']
                id_widget = scrollable_frame.grid_slaves(row=row, column=0)[0]
                first_widget = scrollable_frame.grid_slaves(row=row, column=1)[0]
                second_widget = scrollable_frame.grid_slaves(row=row, column=2)[0]
                used_widget = scrollable_frame.grid_slaves(row=row, column=3)[0]
                where_used_widget = scrollable_frame.grid_slaves(row=row, column=4)[0]

                id_value = id_widget.cget('text')
                first_value = float(first_widget.get())
                second_value = float(second_widget.get())
                used_value = used_widget.get()
                where_used_value = where_used_widget.get()

                if not validate_id(id_value) or not check_difference(id_value[0], first_value, second_value):
                    log_text.insert('end', f"错误: 编号 {id_value} 或称重值不符合规则要求。\n")
                    messagebox.showerror("错误", f"编号 {id_value} 或称重值不符合规则要求。")
                    return

                changes.append((first_value, second_value, used_value, where_used_value, id_value))

        try:
            with conn:
                cursor.executemany(f"""
                    UPDATE {table_name}
                    SET 第一次=?, 第二次=?, 是否已使用=?, 用于何处=?
                    WHERE 编号=?;
                """, changes)
            log_text.insert('end', "数据修改成功\n")
            messagebox.showinfo("完成", "数据修改成功")
            popup.destroy()
        except Exception as e:
            log_text.insert('end', f"发生错误: {e}\n")
            messagebox.showerror("错误", f"发生错误: {e}")

    popup = Toplevel(root)
    window_dict['search_edit_popup'] = popup
    popup.title("查找并修改数据")
    popup.geometry("800x600")
    screen_width = popup.winfo_screenwidth()
    screen_height = popup.winfo_screenheight()
    x = (screen_width - 800) // 2
    y = (screen_height - 600) // 2
    popup.geometry(f"800x600+{x}+{y}")

    Label(popup, text="请输入任务单或编号，编号格式为A0101（5~7位）:").pack(pady=10)
    entry_query = Entry(popup)
    entry_query.pack(pady=10)

    search_by = StringVar(value="id")  # 默认按编号查找

    # 添加 Radio Buttons 来切换查找模式
    frame_toggle = Frame(popup)
    frame_toggle.pack(pady=10)

    radio_id = ttk.Radiobutton(frame_toggle, text="按编号查找", variable=search_by, value="id")
    radio_id.grid(row=0, column=0, padx=5)
    radio_where_used = ttk.Radiobutton(frame_toggle, text="按任务单查找", variable=search_by, value="where_used")
    radio_where_used.grid(row=0, column=1, padx=5)

    btn_search = Button(popup, text="查找", command=search_data)
    btn_search.pack(pady=10)

    # 创建一个可滚动的框架
    frame_details = Frame(popup)
    frame_details.pack(fill='both', expand=True)

    # 添加保存按钮
    btn_save = Button(popup, text="保存更改", command=save_changes)
    btn_save.pack(pady=10)

    # 初始化 scrollable_frame
    scrollable_frame = None

    # 绑定关闭事件
    popup.protocol("WM_DELETE_WINDOW", lambda: on_window_close('search_edit_popup'))

# 获取数据库中所有的表名
def get_all_tables(cursor):
    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
    return [table[0] for table in cursor.fetchall()]

# 显示当前使用的表名
current_table_label = Label(frame_switch, text=f"当前数据源: {table_name}", font=('Arial', 12))
current_table_label.pack(pady=10)

# 创建表名选择变量
selected_table = StringVar(root)
selected_table.set(table_name)  # 默认值

# 更新表名
def update_table_name(new_table_name):
    global table_name
    if new_table_name != table_name:
        confirm = messagebox.askyesno("确认切换", f"确定要更改为 {new_table_name} 吗？")
        if confirm:
            table_name = new_table_name
            current_table_label.config(text=f"当前使用数据源: {table_name}")
            with open(config_file, 'w') as f:
                json.dump({'db_path': db_path, 'table_name': table_name}, f,ensure_ascii=False)
            log_text.insert('end', f"当前数据源已切换为: {table_name}\n")
            messagebox.showinfo("成功", f"当前数据源已切换为: {table_name}")

# 创建表名选择器
def create_table_selector():
    tables = get_all_tables(cursor)
    selected_table.set(table_name)  # 设置默认值
    option_menu = OptionMenu(frame_switch, selected_table, *tables, command=update_table_name)
    option_menu.pack(pady=10)

# 创建表名选择器
create_table_selector()

# 创建按钮
frame_buttons = Frame(frame_main)
frame_buttons.pack(pady=20)
btn_add = Button(frame_buttons, text="手动添加", command=show_add_data_popup)
btn_add.grid(row=0, column=0, padx=10, pady=10)
btn_import = Button(frame_buttons, text="外部导入", command=import_data_to_db)
btn_import.grid(row=0, column=1, padx=10, pady=10)
btn_export = Button(frame_buttons, text="复制到记录", command=export_data_from_db)
btn_export.grid(row=0, column=2, padx=10, pady=10)
btn_view_edit = Button(frame_buttons, text="查找修改", command=search_and_edit_data)
btn_view_edit.grid(row=0, column=3, padx=10, pady=10)

# 运行主循环
root.mainloop()

# 关闭数据库连接
conn.close()